﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;
using Doves.DataAccessLayer;
using Doves.BussinessLayer;
using Doves.Utilities;

namespace Doves.Crawlement
{
    public class ArticleCrawler
    {
        private ArticleCrawlerInputDataType _inputData;


        /// <summary>
        /// Creates an instance of a LinkCrawler.
        /// </summary>
        /// <param name="doc">The input HTML document. May not be null.</param>
        /// 
        public ArticleCrawler(ArticleCrawlerInputDataType inInputData)
        {
            _inputData = inInputData;
        }


        /// <summary>
        /// Remove child node what have pattern match with input ChildPattern
        /// We usually use this method to get full html content of article (with html tag)
        /// </summary>
        /// <param name="inInputNode">Node that you want to manual</param>
        /// <param name="inChildPartten">Pattern of child that you want to remove Ex: ".//h1[@class='Title']"</param>
        /// <returns></returns>
        public HtmlNode RemoveChildNodeWithPattern(HtmlNode inInputNode, string inChildPatten)
        {
            HtmlNodeCollection ChildNodes = inInputNode.SelectNodes(inChildPatten);
            if (ChildNodes != null)
            {
                foreach (HtmlNode child in ChildNodes)
                {
                    //child.ParentNode.RemoveChild(child);
                    if (child.ParentNode == inInputNode)
                    {
                        inInputNode.RemoveChild(child, false);
                    }
                }
            }
            return inInputNode;
        }

        public Article ScanArticleContent()
        {
            if (_inputData.HtmlDoc == null || _inputData.Analizer == null)
            {
                return null;
            }
            Article ReturnArticle = new Article();

            //string AreaNodePattern = "//div[@class='content-center fl']";
            // Selected a article
            HtmlNode AreaNode = _inputData.HtmlDoc.DocumentNode.SelectSingleNode(_inputData.Analizer.AreaNodePatten);
            // If cant get area node then return null
            if (AreaNode == null)
            {
                return null;
            }

            //string TitlePattern = ".//h1[@class='Title']";
            HtmlNode TitleNode = AreaNode.SelectSingleNode(_inputData.Analizer.TitlePattern);

            //string DescPattern = ".//h2[@class='Lead']";
            HtmlNode DescNode = AreaNode.SelectSingleNode(_inputData.Analizer.DescriptionPattern);

            //string ContentPattern = ".//div[@cpms_content='true']";
            HtmlNode ContentNode = AreaNode.SelectSingleNode(_inputData.Analizer.ContentPattern);

            //string AuthorPattern = ".//p[@class='Normal' and @align='right']";
            //HtmlNode AuthorNode = AreaNode.SelectSingleNode(Analizer);

            // If any node is null then cancel this because content of article will not enough
            if (TitleNode == null || DescNode == null || ContentNode == null)
            {
                return null;
            }
            
            // Get article title
            ReturnArticle.Title = TitleNode.InnerText;

            /////////////////////////// Get article description /////////////////////////////////
            // Step1: Remove children in content node what you want
            DescNode = Step1RemoveChildNode(DescNode, NodeType.DescriptionNode);

            // Step 2: Convert content node to string
            string TempDes = DescNode.InnerText;

            // Step3: Correct content string by replacing what you want
            TempDes = Step3CorrectContentByReplacing(TempDes, NodeType.DescriptionNode);

            // Step 4: Interested in the article
            ReturnArticle.Description = TempDes;
            ///////////////////////////////////////////////////////////////////////////////////

            /////////////////////////// Get article content /////////////////////////////////////
            // Step1: Remove children in content node what you want
            ContentNode = Step1RemoveChildNode(ContentNode, NodeType.ContentNode);

            // Step 2: Convert content node to string
            string TempContent = Step2ConvertContentToString(ContentNode);

            // Step3: Correct content string by replacing what you want
            TempContent = Step3CorrectContentByReplacing(TempContent, NodeType.ContentNode);

            // Step 4: Interested in the article
            ReturnArticle.Body = TempContent;
            ///////////////////////////////////////////////////////////////////////////////////

            ReturnArticle.ThumbImage = _inputData.Link.ThumbImage;
            ReturnArticle.ScanTime = DateTime.Now;
            ReturnArticle.Enable = false;
            ReturnArticle.CateId = _inputData.Link.CateId;
            ReturnArticle.CrawlLinkId = _inputData.Link.Id;
            ReturnArticle.fromWebId = (int)_inputData.Link.Zomby.WebId;

            return ReturnArticle;
        }

        /// <summary>
        /// Remove children of node. Apply for content and description
        /// </summary>
        /// <param name="inContentNode"></param>
        /// <param name="inNodeType"></param>
        /// <returns></returns>
        private HtmlNode Step1RemoveChildNode(HtmlNode inContentNode, NodeType inNodeType)
        {
            if (_inputData.KilledChildList != null)
            {
                foreach (ContentKilledChild KilledChild in _inputData.KilledChildList)
                {
                    if ((int)inNodeType == KilledChild.Type)
                    {
                        inContentNode = RemoveChildNodeWithPattern(inContentNode, KilledChild.ChildPattern);
                    }
                }
            }
            
            return inContentNode;
        }

        /// <summary>
        /// We will get innerHtml or OuterHtml of content of article
        /// </summary>
        /// <param name="inContentNode"></param>
        /// <returns></returns>
        private String Step2ConvertContentToString(HtmlNode inContentNode)
        {
            string TempContent = "";
            if ((_inputData.Analizer.IsInnerHtml == null) ? false : (bool)_inputData.Analizer.IsInnerHtml)
            {
                TempContent = inContentNode.InnerHtml;
            }
            else
            {
                TempContent = inContentNode.OuterHtml;
            }
            return TempContent;
        }

        /// <summary>
        /// Replacing data of content or description of article
        /// </summary>
        /// <param name="inContenString"></param>
        /// <param name="inNodeType"></param>
        /// <returns></returns>
        private String Step3CorrectContentByReplacing(String inContenString, NodeType inNodeType)
        {
            if (_inputData.ReplacingList != null)
            {
                foreach (ContentReplacing replacing in _inputData.ReplacingList)
                {
                    if ((int)inNodeType == replacing.Type)
                    {
                        inContenString = inContenString.Replace(replacing.OldChar, replacing.NewChar);
                    }
                }
            }
            
            return inContenString;
        }

    }
}
